#include "Common.h"
#include "IoService.h"
#include "Server.h"
#include "Session.h"

namespace fx {

    ServerPtr Server::Create(tcp::endpoint local_endpoint) 
    {
        return ServerPtr(new Server(local_endpoint));
    }

    void Server::Start()
    {
        if (true == is_running_) {
            return ;
        }
        is_running_ = true;

        boost::system::error_code error;
        do {
            acceptor_.open(endpoint_.protocol(), error);
            if (error) break;
            acceptor_.set_option(tcp::acceptor::reuse_address(true), error);
            if (error) break;
            acceptor_.bind(endpoint_, error);
            if (error) break;
            acceptor_.listen(boost::asio::socket_base::max_connections, error);
            if (error) break;
        } while (false);

        // start accept
        if (!error)
        {
            SessionPtr session = Session::Create(shared_from_this());
            acceptor_.async_accept(session->Socket(),
                boost::bind(&Server::HandleAccept, shared_from_this(), session, _1));
        }
        else
        {
            // error
            std::cout << error.message() << std::endl;
        }
    }

    void Server::Stop()
    {
        if (false == is_running_) {
            return ;
        }

        boost::system::error_code error;
        acceptor_.cancel(error);
        acceptor_.close(error);

        is_running_ = false;
    }

    void Server::HandleAccept(SessionPtr session, const boost::system::error_code& error)
    {
        if (false == is_running_) {
            return ;
        }
        if (!error)
        {
            IoService::Post(boost::bind(&Session::Start, session));
            SessionPtr next_session = Session::Create(shared_from_this());
            acceptor_.async_accept(next_session->Socket(),
                boost::bind(&Server::HandleAccept, shared_from_this(), next_session, _1));
        }
        else {
            std::cout << __FUNCTION__ << ":" << __LINE__ << " " 
                << error.message() << std::endl;
            acceptor_.async_accept(session->Socket(),
                boost::bind(&Server::HandleAccept, shared_from_this(), session, _1));
        }
    }

    Server::Server(tcp::endpoint local_endpoint)
        : acceptor_(IoService::IOS())
        , endpoint_(local_endpoint)
        , is_running_(false)
    {
    }

}
